package org.example.camundaapp.bpm.service;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnDiagram;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnEdge;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnPlane;
import org.camunda.bpm.model.bpmn.instance.bpmndi.BpmnShape;
import org.camunda.bpm.model.bpmn.instance.dc.Bounds;

import org.camunda.bpm.model.bpmn.instance.di.Waypoint;
import org.springframework.beans.factory.annotation.Value;
import java.util.Map;
import java.util.HashMap;

/**
 * 读取JSON并构建BPMN模型，然后输出XML字符串
 * @className: JsonToBpmnConverter
 * @author: ZHRJ
 * @date: 2025-06-24 11:26
 * @Version: 1.0
 * @description:
 */
public class JsonToBpmnConverter {

    @Value("${camunda.modeler.exporter-version}")
    private String exporterVersion;
    /**
     * 将JSON转换为BPMN模型并输出XML字符串
     * @param json
     * @return
     * @throws JSONException
     */
    public String convert(JSONObject json) throws JSONException {
        BpmnModelInstance modelInstance = Bpmn.createEmptyModel();
        Definitions definitions = modelInstance.newInstance(Definitions.class);


        JSONObject processObj2 = json.getJSONObject("process");
        String processName = processObj2.getString("name");

        // 1. 设置基础属性
        definitions.setId("Definitions_" + processName + "_" + System.currentTimeMillis());
        definitions.setTargetNamespace("http://bpmn.io/schema/bpmn");
        definitions.setAttributeValue("exporter", "Camunda Modeler");
        definitions.setAttributeValue("exporterVersion", exporterVersion);
        definitions.setAttributeValueNs("http://camunda.org/schema/modeler/1.0", "executionPlatform", "Camunda Platform");
        definitions.setAttributeValueNs("http://camunda.org/schema/modeler/1.0", "executionPlatformVersion", exporterVersion);
        //definitions.setTargetNamespace("http://camunda.org/examples"); // 用于唯一标识流程定义的命名空间，避免不同流程之间的 ID 冲突

        // 3. 设置exporter相关属性（无命名空间前缀）
        definitions.setAttributeValue("exporter", "Camunda Modeler");
        definitions.setAttributeValue("exporterVersion", exporterVersion);

        // 4. 设置modeler命名空间的扩展属性
        definitions.setAttributeValueNs(
                "http://camunda.org/schema/modeler/1.0", // modeler命名空间URI
                "executionPlatform",                     // 属性名（local name）
                "Camunda Platform"                       // 属性值
        );
        definitions.setAttributeValueNs(
                "http://camunda.org/schema/modeler/1.0", // modeler命名空间URI
                "executionPlatformVersion",              // 属性名（local name）
                exporterVersion                                  // 属性值
        );


        JSONObject processObj = json.getJSONObject("process");
        // 正确的顺序应该是：先将process添加到definitions中（即模型树中），然后再创建BpmnPlane并引用它。
        Process process = modelInstance.newInstance(Process.class);

        process.setId(processObj.getString("id"));
        process.setExecutable(true); // 显式声明为可执行流程
        process.setName(processObj.getString("name"));

        // 先将 Process 添加到模型根元素 Definitions
        definitions.addChildElement(process);
        // 立即同步模型实例的根元素
        modelInstance.setDefinitions(definitions);

        // 创建BPMN Diagram并添加到definitions（而非process的extensionElements）
        BpmnDiagram bpmnDiagram = modelInstance.newInstance(BpmnDiagram.class);
        BpmnPlane bpmnPlane = modelInstance.newInstance(BpmnPlane.class);
        bpmnPlane.setId("BPMNPlane_" + System.currentTimeMillis());
        bpmnPlane.setBpmnElement(process);
        bpmnDiagram.addChildElement(bpmnPlane);
        definitions.addChildElement(bpmnDiagram);

        // 为每个节点添加图形位置信息
        int baseX = 100;
        int spacing = 150;
        int y = 100;
        int width = 100;
        int height = 80;

        // 存储节点位置信息用于生成连接线
        Map<String, Bounds> nodeBoundsMap = new HashMap<>();

        JSONArray nodes = processObj.getJSONArray("nodes");
        for (int i = 0; i < nodes.size(); i++) {
            JSONObject node = nodes.getJSONObject(i);
            String id = node.getString("id");
            String type = node.getString("type");
            String name = node.getString("name");
            FlowNode flowNode = null;


            switch (type) {
                case "startEvent":
                    flowNode = modelInstance.newInstance(StartEvent.class);
                    break;
                case "task":
                    flowNode = modelInstance.newInstance(Task.class);
                    break;
                case "endEvent":
                    flowNode = modelInstance.newInstance(EndEvent.class);
                    break;
                case "userTask":
                    flowNode = modelInstance.newInstance(UserTask.class);
                    break;
                case "serviceTask":
                    flowNode = modelInstance.newInstance(ServiceTask.class);
                    break;
                case "exclusiveGateway":
                    flowNode = modelInstance.newInstance(ExclusiveGateway.class);
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported node type: " + type);
            }
            if (flowNode != null) {
                flowNode.setId(id);
                flowNode.setName(name);

               /* // 文档注释处理
                if (node.has("documentation")) {
                    Documentation documentation = modelInstance.newInstance(Documentation.class);
                    documentation.setTextContent(node.getString("documentation"));
                    flowNode.addChildElement(documentation);
                }

                // 处理Camunda扩展属性
                if (node.has("camunda:asyncBefore")) {
                    flowNode.setAttributeValueNs(
                            "http://camunda.org/schema/1.0/bpmn",
                            "asyncBefore",
                            node.getString("camunda:asyncBefore")
                    );
                }*/

                process.addChildElement(flowNode);

                BpmnShape shape = modelInstance.newInstance(BpmnShape.class);
                shape.setBpmnElement(flowNode);
                shape.setExpanded(true); // 控制是否展开
                //shape.setTextContent("流程节点图形描述");

                Bounds bounds = modelInstance.newInstance(Bounds.class);
                bounds.setX(baseX + i * spacing);
                bounds.setY(y);
                bounds.setWidth(width);
                bounds.setHeight(height);

                shape.setBounds(bounds);
                bpmnPlane.addChildElement(shape);
                //process.addChildElement(shape);
            }
        }

        JSONArray flows = processObj.getJSONArray("sequenceFlows");
        for (int i = 0; i < flows.size(); i++) {
            JSONObject flow = flows.getJSONObject(i);
            String id = flow.getString("id");
            String sourceId = flow.getString("sourceId");
            String targetId = flow.getString("targetId");
            FlowNode source = (FlowNode) modelInstance.getModelElementById(sourceId);
            FlowNode target = (FlowNode) modelInstance.getModelElementById(targetId);
            // 创建SequenceFlow并关联到模型实例
            SequenceFlow sequenceFlow = modelInstance.newInstance(SequenceFlow.class);
            sequenceFlow.setId(id);
            sequenceFlow.setSource(source);
            sequenceFlow.setTarget(target);
            
            // 添加incoming和outgoing引用
            source.getOutgoing().add(sequenceFlow);
            target.getIncoming().add(sequenceFlow);
            
            // 确保sequenceFlow正确关联到流程
            // 创建新的SequenceFlow实例
            SequenceFlow newSequenceFlow = modelInstance.newInstance(SequenceFlow.class);
            newSequenceFlow.setId(sequenceFlow.getId());
            newSequenceFlow.setName(sequenceFlow.getName());
            
            // 设置源和目标节点
            newSequenceFlow.setSource(source);
            newSequenceFlow.setTarget(target);
            
            // 添加到流程定义
            process.addChildElement(newSequenceFlow);
            
            // 创建BPMNEdge并添加到BpmnPlane
            BpmnEdge edge = modelInstance.newInstance(BpmnEdge.class);
            edge.setId(newSequenceFlow.getId() + "_di");
            edge.setBpmnElement(newSequenceFlow);

            // 获取源节点和目标节点的位置信息
            Bounds sourceBounds = nodeBoundsMap.get(sourceId);
            Bounds targetBounds = nodeBoundsMap.get(targetId);

            // 计算起点和终点的waypoint（连接线的路径点）
            Waypoint startWaypoint = modelInstance.newInstance(Waypoint.class);
            startWaypoint.setX(sourceBounds.getX() + sourceBounds.getWidth());
            startWaypoint.setY(sourceBounds.getY() + sourceBounds.getHeight() / 2);

            Waypoint endWaypoint = modelInstance.newInstance(Waypoint.class);
            endWaypoint.setX(targetBounds.getX());
            endWaypoint.setY(targetBounds.getY() + targetBounds.getHeight() / 2);

            edge.addChildElement(startWaypoint);
            edge.addChildElement(endWaypoint);
            bpmnPlane.addChildElement(edge);
        }


        // 将模型输出为XML字符串
        return Bpmn.convertToString(modelInstance);
    }
}
